home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj0190.arc / SCHULMAN.LST < prev    next >
File List  |  1989-12-19  |  10KB  |  368 lines

  1. _STALKING GENERAL PROTECTION FAULTS: PART I_
  2. by Andrew Schulman
  3.  
  4. [LISTIN╟ ONE]
  5.  
  6. /¬ FFFF.C
  7.     -- causes GP fault in real mode on 286/386, and in Virtual 86 mode
  8.     -- catch it in real mode
  9.     -- can't catch it in Virtual 86 mode
  10.  
  11. Turbo C: tcc ffff.c
  12. Microsoft C: cl ffff.c
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <dos.h>
  17. #include "gpfault.h"
  18.  
  19. void (interrupt far *old)();
  20.  
  21. void fini(char *msg, int exit_code)
  22. {
  23.     puts(msg);
  24.     _dos_setvect(INT_GPFAULT, old);
  25.     exit(exit_code);
  26. }
  27.  
  28. void far my_exit(void) { fini("Bye!", 1); }
  29.  
  30. void interrupt far handler(REG_PARAMS r)
  31. {
  32.     printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
  33.     /* change CS:IP on stack so control is "returned" to my_exit */
  34.     /* this is an alternative to using longjmp() */
  35.     r.cs = FP_SEG(my_exit);
  36.     r.ip = FP_OFF(my_exit);
  37. }   
  38.  
  39. main()
  40. {
  41.     int *p = (int *) -1;
  42.     old = _dos_getvect(INT_GPFAULT);
  43. #ifndef CRASH_AT
  44.     _dos_setvect(INT_GPFAULT, handler);
  45. #endif
  46.     printf("int at %p is ", p);
  47.     printf("%04X\n", *p);
  48.     /*NOTREACHED on 286/386 */
  49.     fini("Done!", 0);
  50. }
  51.  
  52.  
  53.  
  54. [LISTIN╟ TWO]
  55.  
  56. /¬ GPFAULT.H
  57.     -- REG_PARAM structure represents stack at entry to interrupt handler
  58.     -- CPU pushes flags, CS:IP, and, for protected-mode INT 08-0D,
  59.        an error code
  60.     -- Compiler pushes all other registers at entry to interrupt function
  61.     -- Turbo C pushes registers in a strange order
  62.     -- Watcom C 386 7.0 also pushes FS and GS registers (unfortunately
  63.        MetaWare High C for MS-DOS 386 1.5 does not)
  64.  
  65.     -- replace Microsoft C 5.1 FP_SEG, FP_OFF macros with ones that don't
  66.        requires lvalues
  67.     -- keep Watcom C 386 7.0 FP_SEG, etc. -- these work for 48-bit pointers
  68.     -- for MetaWare High C for 386 MS-DOS, need our own 48-bit FP_SEG, etc.
  69. */
  70.  
  71. #ifdef InstantC_16M
  72. /* Rational Systems Instant-C/16M protected-mode C interpreter */
  73. #define DOS16M
  74. #define PROT_MODE
  75. #endif
  76.  
  77. typedef struct {
  78. #if defined(__WATCOMC__) && defined(__386__)
  79.     unsigned gs,fs;
  80. #endif
  81. #ifdef __TURBOC__
  82.     unsigned bp,di,si,ds,es,dx,cx,bx,ax;
  83. #else
  84.     unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax;     /* same as PUSHA */
  85. #endif
  86. #ifdef PROT_MODE
  87.     unsigned err_code;                          /* for pmode INT 08-0D */
  88. #endif
  89.     unsigned ip,cs,flags;
  90.     } REG_PARAMS;
  91.  
  92. #ifdef __TURBOC__
  93. #define _dos_setvect(x,y)   setvect(x,y)
  94. #define _dos_getvect(x)     getvect(x)
  95. #endif
  96.  
  97. #define INT_GPFAULT         0x0D
  98.  
  99. /* 386 protected-mode: far pointer is 48 bits; near pointer is 32 bits */
  100. /* thus, 386 pmode near pointer can hold a real-mode far pointer */
  101. #ifdef __HIGHC__
  102. #define real_far            _near
  103. #define prot_far            _far
  104. #define far                 _far
  105. #else
  106. #if defined(__WATCOMC__) && defined(__386__)
  107. #define real_far            near
  108. #define prot_far            far
  109. #endif
  110. #endifè
  111. #ifdef __HIGHC__
  112. /* use overlay struct: no High C support for 48-bit immediate values */
  113. /* remember that unsigned is 32 bits, short is 16 bits */
  114. typedef struct { unsigned off; short seg; } overlay;
  115.  
  116. #define FP_SEG(fp)          ((overlay prot_far *) &(fp))->seg
  117. #define FP_OFF(fp)          ((overlay prot_far *) &(fp))->off
  118. #else
  119. #if (!(defined(__WATCOMC__) && defined(__386__)))
  120. /* Microsoft C FP_SEG() and FP_OFF() require an lvalue:  yuk! */
  121. #ifdef FP_SEG
  122. #undef FP_SEG
  123. #undef MK_FP
  124. #undef FP_OFF
  125. #endif
  126. #define FP_SEG(fp)          (((UL)(fp)) >> 16)
  127. #define MK_FP(seg,off)      ((FP)(UL)(((UL)(seg) << 16) | (off)))
  128. #define FP_OFF(fp)          ((unsigned)(fp))
  129. #endif
  130. #endif
  131.  
  132. typedef unsigned long UL;
  133. typedef void far *FP;
  134. typedef enum { FALSE, TRUE } BOOL;
  135.  
  136. #ifdef __HIGHC__
  137. #pragma Calling_convention(C_interrupt | _FAR_CALL);
  138. typedef void (*IPROC)();
  139. #pragma Calling_convention();
  140. #else
  141. typedef void (interrupt far *IPROC)();
  142. #endif
  143.  
  144.  
  145.  
  146. [LISTIN╟ THREE]
  147.  
  148. /¬ GPFAULT.C -- for AI Architects OS/286 or Rational Systems DOS/16M
  149.  
  150. for AI Architects:
  151.     cl -AL -Ox -Gs2 -c -DPROT_MODE gpfault.c
  152.     link gpfault,gpfault,gpfault/map,\os286\llibce;
  153.     \os286\express gpfault
  154.     cp gpfault
  155.  
  156. for DOS16M:
  157.     if not exist dos16lib.obj cl -AL -Ox -Gs2 -c source\dos16lib.c
  158.     cl -AL -Ox -Gs2 -c -DPROT_MODE -DDOS16M -Zi gpfault.c
  159.     link /co preload crt0_16m pml gpfault dos16lib /noe,gpfault;
  160.     makepm gpfault
  161.     splice gpfault gpfault
  162.     d gpfault
  163. */
  164.  
  165. #include <stdio.h>
  166. #include <stdlib.h>
  167. #include <setjmp.h>
  168. #include <string.h>
  169. #include <dos.h>
  170. #ifdef DOS16M
  171. #include "dos16.h"
  172. #endif
  173. #include "gpfault.h"
  174.  
  175. #define IN_MY_CODE          11593
  176. #define IN_USER_CODE        16843
  177. #define IN_HANDLER          40311
  178.  
  179. unsigned whereami = IN_MY_CODE;     /* need our own protection for this */
  180. jmp_buf toplevel;
  181. jmp_buf toplevel_copy = {0};        /* initialized, in a different segment */
  182. unsigned legal = 0;                 /* just a legal address to bang on */
  183. void (interrupt far *old_int13handler)();
  184.  
  185. void interrupt far int13handler(REG_PARAMS r);  /* GP fault handler */
  186. void goto_toplevel(void);       /* longjump out of handler */
  187. void revert(void);              /* restore default handler */
  188. void fail(char *msg, FP fp);    /* fail by calling default handler */
  189.  
  190. main(int argc, char *argv[])
  191. {
  192.     char buf[255];
  193.     unsigned far *fp;
  194.     unsigned data;
  195.  
  196.     old_int13handler = _dos_getvect(INT_GPFAULT);
  197.     _dos_setvect(INT_GPFAULT, int13handler);
  198.  
  199.     printf("'Q' to quit, '!' to reinstall default GP Fault handler\n");
  200.     printf("%Fp is a legal address to poke\n", &legal);
  201.     /* next line helps illustrate limitations of protection */
  202.     printf("%Fp is not a legal address to poke\n", &legal-1);
  203.     
  204.     setjmp(toplevel);
  205.     whereami = IN_MY_CODE;
  206.     memcpy(toplevel_copy, toplevel, sizeof(jmp_buf));
  207.     
  208.     for (;;)
  209.     {
  210.         printf("$ ");
  211.         *buf = '\0';
  212.         gets(buf);
  213.         
  214.         if (toupper(*buf) == 'Q')
  215.             break;
  216.         else if (*buf == '!')
  217.         {
  218.             revert();
  219.             continue;
  220.         }
  221.     
  222.         sscanf(buf, "%Fp %u", &fp, &data);
  223.         whereami = IN_USER_CODE;
  224.         *fp = data;     /* the crucial line of code */
  225.         printf("poked %Fp with %u\n", fp, *fp);
  226.         whereami = IN_MY_CODE;
  227.     }
  228.  
  229.     revert();
  230.     puts("Bye");
  231.     return 0;
  232. }
  233.  
  234. void revert(void)
  235. {
  236.     _dos_setvect(INT_GPFAULT, old_int13handler);
  237. }
  238.  
  239. void fail(char *msg, FP fp)
  240. {
  241.     (fp) ? printf(msg, fp) : puts(msg);
  242.     revert();
  243.     _chain_intr(old_int13handler);
  244. }
  245.  
  246. void goto_toplevel(void)
  247. {
  248.     if (memcmp(toplevel, toplevel_copy, sizeof(jmp_buf)) == 0)
  249.         longjmp(toplevel, -1);
  250.     else
  251.         fail("Toplevel context has been trompled", 0);
  252. }
  253.             
  254. void interrupt far int13handler(REG_PARAMS r)
  255. {
  256.     switch (whereami)
  257.     {
  258.         case IN_HANDLER:
  259.             fail("\nDouble fault at %Fp\n", MK_FP(r.cs, r.ip));
  260.             /*NOTREACHED*/
  261.         case IN_MY_CODE:
  262.             fail("\nInternal error at %Fp\n", MK_FP(r.cs, r.ip));
  263.             /*NOTREACHED*/
  264.         case IN_USER_CODE:
  265.             whereami = IN_HANDLER;
  266.             _enable();  /* reenable interrupts */
  267.             /* we could use Intel LAR and LSL instructions here to
  268.             figure out why GP fault took place:  did we try to write
  269.             into code?  or did offset overrun segment limit? */
  270.             printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
  271.             if (r.err_code)
  272.                 printf("Error code %04X\n", r.err_code);
  273.             printf("<ES %04X> <DS %04X> <DI %04X> <SI %04X>\n", 
  274.                 r.es, r.ds, r.di, r.si);
  275.             printf("<AX %04X> <BX %04X> <CX %04X> <DX %04X>\n", 
  276.                 r.ax, r.bx, r.cx, r.dx);
  277.             goto_toplevel();
  278.             /*NOTREACHED*/
  279.         default:
  280.             whereami = IN_HANDLER;
  281.             _enable();
  282.             puts("whereami flag got trompled");
  283.             goto_toplevel();
  284.             /*NOTREACHED*/
  285.     }
  286. }
  287.  
  288. #ifdef DOS16M
  289. void _dos_setvect(unsigned intno, IPROC isr)
  290. {
  291.     D16pmInstall(intno, FP_SEG(isr), FP_OFF(isr), NULL);
  292. }
  293.  
  294. IPROC _dos_getvect(unsigned intno)
  295. {
  296.     IPROC isr;
  297.     D16pmGetVector(intno, (INTVECT *) &isr);
  298.     return isr;
  299. }
  300. #endif
  301.  
  302.  
  303. Examplσ 1║ Thi≤ codσ wil∞ causσ ß G╨ faul⌠ iε protecteΣ modσ 
  304.  
  305.         main()
  306.         {
  307.             int far *fp = (int far *) main;
  308.             *fp = rand();
  309.             main();
  310.         }
  311.  
  312. Examplσ 2║ Iµ thi≤ prograφ G╨ faults¼ it'≤ becausσ oµ aε erro≥ b∙ ì
  313. thσ user¼ no⌠ b∙ thσ applicatioε itself.
  314.  
  315.         main(int argc, char *argv[])
  316.         {
  317.             int far *fp = (int far *) atol(argv[1]);
  318.             *fp = atoi(argv[2]);
  319.         }
  320.  
  321.  
  322. Figurσ 1║ ┴ G╨ faul⌠ dump
  323.  
  324.         Session Title: UR/Forth
  325.             SYS1943: A program caused a protection violation.
  326.             TRAP 000D
  327.             AX=2092 BX=0000 CX=FFFF DX=3FC2 BP=FFFA
  328.             SI=05EA DI=05E4 DS=00C7 ES=0000 FLG=2206
  329.             CS=0227 IP=2093 SS=00C7 SP=FBFC MSW=FFED
  330.             CSLIM=FFFE SSLIM=FFFF DSLIM=FFFF ESLIM=****
  331.             CSACC=DF SSACC=F3 DSACC=F3 ESACC=**
  332.             ERRCD=0000 ERLIM=**** ERACC=**
  333.                 End the program
  334.  
  335. Figurσ 2║ ┴ GPFAULT.EX╨ session
  336.  
  337.  
  338.         C:\DOS16M>gpfault
  339.         DOS/16M Protected Mode Run-Time     Version 3.25
  340.         Copyright (C) 1987,1988,1989 by Rational Systems, Inc.
  341.         'Q' to quit, '!' to reinstall default GP fault handler
  342.         00A0:04C6 is a legal address to poke
  343.         00A0:04C4 is not a legal address to poke
  344.         $ 1234:5678 666
  345.         Protection violation at 0088:00C5!
  346.         Error code 1234
  347.         <ES 00A0> <DS 00A0> <DI 1AC0> <SI 0082>
  348.         <AX 0015> <BX 0BF8> <CX 0015> <DX 0000>
  349.         $ 00A0:04C4 666
  350.         poked 00A0:04C4 with 666
  351.         $ 00A0:04C2 1
  352.         poked 00A0:04C2 with 1
  353.         $ 0088:00C5 666
  354.         Protection violation at 0088:00CB!
  355.         <ES 0088> <DS 00A0> <DI 1AC0> <SI 0082>
  356.         <AX 029A> <BX 00CB> <CX 0015> <DX 0000>
  357.         $ 0:0 0
  358.         Protection violation at 0088:00CB!
  359.         <ES 0000> <DS 00A0> <DI 1AC0> <SI 0082>
  360.         <AX 0000> <BX 0000> <CX 0015> <DX 0000>
  361.         $ !
  362.         $ 0:0 0
  363.         DOS/16M: Unexpected Interrupt=000D  at 0088:00CB
  364.         code=0000 ss=00A0 ds=00A0 es=0000 
  365.         ax=0000 bx=0000 cx=0015 dx=0000 sp=1982 bp=1A92 si=0082 di=1AC0 
  366.         C:\DOS16M>
  367.  
  368.